"""
Author: runyu.ma

symbol_table.py
"""


class Symbol:
    """
    表示一个符号：
    - name: 符号名
    - info: 与符号相关的属性字典，例如类型、内存位置等
    """
    def __init__(self, name: str, info: dict = None):
        self.name = name
        self.info = info or {}

    def __repr__(self):
        return f"Symbol(name={self.name!r}, info={self.info})"


class SymbolTable:
    """
    符号表：通过一个栈（列表）来管理嵌套作用域，
    每个作用域用一个 dict 存放符号名到 Symbol 对象的映射。
    """
    def __init__(self):
        # 栈底即全局作用域
        self.scopes = []
        self.symbols = {}

    def enter_scope(self, sname):
        """进入一个新的作用域（在栈顶 push 一个空字典）"""
        self.scopes.append(sname)

    def exit_scope(self):
        """退出当前作用域（pop 最顶层的字典）"""
        if len(self.scopes) == 1:
            raise RuntimeError("不能退出全局作用域")
        self.scopes.pop()

    def add(self, name: str, info: dict = None):
        """
        在当前（最顶层）作用域中添加一个符号。
        如果已存在则抛出异常或覆盖，视需求而定。
        """
        fullname = '::'.join(self.scopes + [name])
        if fullname in self.symbols:
            raise KeyError(f"符号 {name!r} 已在当前作用域中定义")
        self.symbols[fullname] = Symbol(name, info)

    def lookup(self, name: str) -> Symbol:
        """
        从当前作用域往外层作用域查找符号，找到则立即返回，
        找不到则返回 None。
        """
        # 从栈顶到栈底遍历
        deepth = len(self.scopes)
        while deepth > 0:
            fullname = '::'.join(self.scopes[0:deepth] + [name])
            if fullname in self.symbols:
                return self.symbols[fullname]
            deepth = deepth - 1
        return None

    def lsvisiable(self):
        """
        展示现在这个scope中所有包含ival的变量
        """
        ret = {}
        sname = '::'.join(self.scopes[0:])
        for k in self.symbols:
            didx = k.rfind('::')
            scop2 = k[0:didx]
            name2 = k[didx+2:]
            #print(sname, scop2, name2)
            if sname.startswith(scop2) and 'ival' in self.symbols[k].info:
                #and not name2 in ret:
                ret[name2] = self.symbols[k].info['ival']
            if sname.startswith(scop2) and 'astobj' in self.symbols[k].info:
                ret[name2] = self.symbols[k].info['astobj']
        return ret

    def __repr__(self):
        s = [f'#### SYMBOL TABLE top scopes is {self.scopes[0]}\n#### NOW scope is {self.scopes}']
        for k in self.symbols:
            s.append(f"{k} : {self.symbols[k]}")
        s.append('####')
        return "\n".join(s)


def build_default_symtab():
    ret = SymbolTable()
    ret.enter_scope('g')
    return ret
